import json
import datetime
from django.shortcuts import render, redirect, HttpResponse
from django.http import JsonResponse
from django.views.decorators.csrf import csrf_exempt
from django.utils.safestring import mark_safe
from django.urls import reverse
from web import models
from web.forms.issues import IssuesModelForm, IssuesReplyModelForm, InviteModelForm
from utils.pagenation import Pagenation
from utils.common import uid


class CheckFilter(object):
    def __init__(self, request, param_name, data_list):
        self.request = request
        self.param_name = param_name  # status
        self.data_list = data_list  # (1, '新建'),(2, '处理中'),(3, '已解决'),(4, '已忽略'),(5, '待反馈'),(6, '已关闭'),(7, '重新打开'),

    def __iter__(self):
        # 遍历 数据库 的选项，判断是否在GET传递过来的里面
        for status_item in self.data_list:
            key = str(status_item[0])
            value = status_item[1]
            get_condition_list = self.request.GET.getlist(self.param_name)  # GET传递过来的指定参数 的列表
            ck = ""
            if key in get_condition_list:
                # 如果数据 在 传递过来的列表里面
                ck = "checked"
                get_condition_list.remove(key)
            else:
                get_condition_list.append(key)
            # 获取url原本携带的所有参数
            query_dict = self.request.GET.copy()  # {'page': ['1'], 'status': ['3', '4', '5']}
            # 根据传递过来的指定参数 ，修改对应url参数的值
            query_dict.setlist(self.param_name, get_condition_list)
            # 选中条件后跳转至第一页，也就是把url参数里面的page参数去掉
            if 'page' in query_dict:
                query_dict.pop('page')
            # 转换成 url参数的格式：page=1&status=1&status=2
            param_url = query_dict.urlencode()
            if param_url:
                url = "{}?{}".format(self.request.path_info, param_url)
            else:
                url = self.request.path_info
            html = "<a href='{url}'><input type='checkbox' {ck}/>{text}</a>".format(url=url, text=value, ck=ck)
            yield mark_safe(html)


class SelectFilter(object):
    def __init__(self, request, param_name, data_list):
        self.request = request
        self.param_name = param_name
        self.data_list = data_list
        pass

    def __iter__(self):
        yield mark_safe("<select class='select2' style='width:100%' multiple='multiple'>")

        op = ""
        for item in self.data_list:
            key = str(item[0])
            value = item[1]
            # 获取url传递过来的参数，然后判断当前值 是否在里面
            get_condition_list = self.request.GET.getlist(self.param_name)  # GET传递过来的指定参数 的列表
            ck = ""
            if key in get_condition_list:
                # 如果数据 在 传递过来的列表里面
                ck = "selected"
                get_condition_list.remove(key)
            else:
                get_condition_list.append(key)
            # 获取url原本携带的所有参数
            query_dict = self.request.GET.copy()  # {'page': ['1'], 'status': ['3', '4', '5']}
            # 根据传递过来的指定参数 ，修改对应url参数的值
            query_dict.setlist(self.param_name, get_condition_list)
            # 选中条件后跳转至第一页，也就是把url参数里面的page参数去掉
            if 'page' in query_dict:
                query_dict.pop('page')
            # 转换成 url参数的格式：page=1&status=1&status=2
            param_url = query_dict.urlencode()
            if param_url:
                url = "{}?{}".format(self.request.path_info, param_url)
            else:
                url = self.request.path_info
            html = "<option value='{url}' {ck}>{text}</option>".format(url=url, text=value, ck=ck)
            yield mark_safe(html)
        yield mark_safe("</select>")


def issues(request, project_id):
    if request.method == "GET":
        # 获取问题列表
        data_dict = {
            "project": request.tracer.project,
        }
        # 所有的URL筛选条件
        condition_list = ['status', 'priority', 'issues_type', 'assign', 'attention', 'milestone']
        for c in condition_list:
            # 遍历，然后获取URL传递过来的参数列表里面取值
            data_list = request.GET.getlist(c)
            if data_list:
                # 匹配到的，也就是传参了的，则添加在过滤条件字典里边，"status__in":[1,2],
                data_dict["{c}__in".format(c=c)] = data_list

        queryset = models.Issues.objects.filter(**data_dict)
        # 设置分页
        page_object = Pagenation(request, queryset, 6)
        page_queryset = page_object.page_queryset
        page_string = page_object.html()
        # 获取项目的问题类型
        project_issues_type = models.IssuesType.objects.filter(project=request.tracer.project).values_list('id',
                                                                                                           'title')
        # 获取项目的所有人员，包括项目创建者
        project_user_list = [(request.tracer.project.create_user_id, request.tracer.project.create_user.user_name), ]
        join_user_tuple = models.ParticipatorInfo.objects.filter(project=request.tracer.project).values_list(
            'participator_id', 'participator__user_name')
        if join_user_tuple:
            project_user_list.extend(join_user_tuple)
        # 获取项目所有的里程碑（模块）milestone
        milestone_list = models.Milestone.objects.filter(project_id=project_id).values_list('id', 'title')
        # 新建问题表单
        form = IssuesModelForm(request)
        invite_form = InviteModelForm()
        return render(request, 'issues.html', {
            "form": form,
            "invite_form": invite_form,
            "issues_object_list": page_queryset,
            "page_string": page_string,
            "status_filter": CheckFilter(request, 'status', models.Issues.status_choices),
            "priority_filter": CheckFilter(request, 'priority', models.Issues.priority_choices),
            "type_filter": CheckFilter(request, 'issues_type', project_issues_type),
            "assign_filter": SelectFilter(request, 'assign', project_user_list),
            "attention_filter": SelectFilter(request, 'attention', project_user_list),
            "milestone_filter": SelectFilter(request, 'milestone', milestone_list),
        })
    # 提交问题
    form = IssuesModelForm(request, data=request.POST)
    if form.is_valid():
        form.instance.project = request.tracer.project
        form.instance.creator = request.tracer.user
        # print(form.data,"look this")
        form.save()
        return JsonResponse({"status": True})
    return JsonResponse({"status": False, "error": form.errors})


# ''' 问题详情 '''
def issues_detail(request, project_id, issues_id):
    # 展示问题详情
    if request.method == "GET":
        issues_object = models.Issues.objects.filter(id=issues_id, project_id=project_id).first()
        # print(dir(issues_object),issues_object._meta.get_field("priority").verbose_name)
        form = IssuesModelForm(request, instance=issues_object)
        content = {
            "form": form,
            "issues_object": issues_object,
        }
        return render(request, "issues_detail.html", content)
    # 提交回复==


# ''' 获取问题回复列表及 进行问题回复 '''
@csrf_exempt
def issues_reply(request, project_id, issues_id):
    # 判断是否可以评论和是否可以操作这个问题
    if request.method == "GET":
        reply_list = models.IssuesReply.objects.filter(issues_id=issues_id, issues__project=request.tracer.project)
        # 将queryset转换成json
        data_list = []
        for row in reply_list:
            data = {
                'id': row.id,
                'reply_type_text': row.get_reply_type_display(),
                'content': row.content,
                'creator': row.creator.user_name,
                'datetime': row.create_datetime.strftime("%Y-%m-%d %H:%M:%S"),
                'parent_id': row.reply_id,
            }
            data_list.append(data)
        return JsonResponse({"status": True, "data": data_list})
    # 提交回复操作
    form = IssuesReplyModelForm(data=request.POST)
    if form.is_valid():
        form.instance.reply_type = 2
        form.instance.issues_id = issues_id
        form.instance.creator = request.tracer.user
        instance = form.save()
        info = {
            'id': instance.id,
            'reply_type_text': instance.get_reply_type_display(),
            'content': instance.content,
            'creator': instance.creator.user_name,
            'datetime': instance.create_datetime.strftime("%Y-%m-%d %H:%M"),
            'parent_id': instance.reply_id
        }
        return JsonResponse({"status": True, "data": info})
    return JsonResponse({'status': False, 'errors': form.errors})


@csrf_exempt
def issues_change(request, project_id, issues_id):
    # 向回复表插入记录
    def insert_reply(content):
        insert_instance = models.IssuesReply.objects.create(
            reply_type=1,
            issues_id=issues_id,
            content=content,
            creator_id=request.tracer.user.id,
        )
        insert_dict = {
            'id': insert_instance.id,
            'reply_type_text': insert_instance.get_reply_type_display(),
            'content': insert_instance.content,
            'creator': insert_instance.creator.user_name,
            'datetime': insert_instance.create_datetime.strftime("%Y-%m-%d %H:%M"),
            'parent_id': insert_instance.reply_id
        }
        return insert_dict

    issues_object = models.Issues.objects.filter(id=issues_id, project_id=project_id).first()
    post_dict = json.loads(request.body.decode("utf-8"))
    name = post_dict.get("name")
    value = post_dict.get("value")
    # 判断是否可以为空，根据字符串获取字段的对象
    fields_object = models.Issues._meta.get_field(name)
    # 先判单 要变更的字段的类型 文本、FK外键、choices下拉选项、m2m处理
    if name in ['subject', 'desc', 'start_date', 'end_date']:
        # print(fields_object.verbose_name,fields_object.null)
        # 先判断传递过来的值是否为空
        if not value:
            # 当传递的值为空,接着判断数据库是否允许为空
            if not fields_object.null:
                # 数据库不允许为空
                return JsonResponse({"status": False, "errors": "该项不允许为空"})
            else:
                # 数据库允许为空，则设置更新数据库该字段为空
                setattr(issues_object, name, None)
                issues_object.save()
                reply_content = "{}更新为空".format(fields_object.verbose_name)

        # 当传递过来的值不为空
        else:
            setattr(issues_object, name, value)
            issues_object.save()
            if name == "desc":
                # 防止问题描述过长把页面撑开
                reply_content = "更新了{}".format(fields_object.verbose_name)
            else:
                reply_content = "{}更新为{}".format(fields_object.verbose_name, value)
        return JsonResponse({"status": True, "data": insert_reply(reply_content)})
    # 处理 FK外键类型
    if name in ['issues_type', 'milestone', 'assign', 'parent']:
        if not value:
            # 当传递的值为空，接着判断数据库字段是否允许为空
            if not fields_object.null:
                # 数据库不允许为空
                return JsonResponse({"status": False, "errors": "该项不允许为空"})
            else:
                # 数据库允许为空
                setattr(issues_object, name, None)
                issues_object.save()
                reply_content = "{}更新为空".format(fields_object.verbose_name)
        else:
            # 当前端改变的是指派者时需单独处理
            if name == "assign":
                # 先判断是不是项目的创建者
                if value == str(request.tracer.project.create_user_id):
                    instance = request.tracer.project.create_user
                else:
                    # 判断是否项目参与者
                    project_user = models.ParticipatorInfo.objects.filter(project_id=project_id,
                                                                          participator_id=value).first()
                    if not project_user:
                        instance = None
                    else:
                        instance = project_user.participator
                if not instance:
                    return JsonResponse({"status": False, "errors": "值不存在"})
                else:
                    setattr(issues_object, name, instance)
                    issues_object.save()
                    reply_content = "{}更新为{}".format(fields_object.verbose_name, str(instance))

            else:
                # 当传递的值不为空，则先判断传递的值是否是自己的值
                # instance = models.IssuesType.objects.filter(id=value).first()
                # 自动到 字段关联的 表 查询
                instance = fields_object.rel.model.objects.filter(id=value, project_id=project_id).first()
                if not instance:
                    return JsonResponse({"status": False, "errors": "值不存在"})
                setattr(issues_object, name, instance)
                issues_object.save()
                # reply_content = "{}更新为{}".format(fields_object.verbose_name,instance.__str__())
                reply_content = "{}更新为{}".format(fields_object.verbose_name, str(instance))
        return JsonResponse({"status": True, "data": insert_reply(reply_content)})
    # 处理choices下拉选项
    if name in ['priority', 'status', 'mode']:
        selected_text = ""
        choices_tuple = fields_object.choices  # 根据字段对象获取 choices属性值
        for k, v in choices_tuple:
            if str(value) == str(k):
                selected_text = v
        if not selected_text:
            return JsonResponse({"status": False, "errors": "该选项不存在"})
        else:
            setattr(issues_object, name, value)
            issues_object.save()
            reply_content = "{}变更为{}".format(fields_object.verbose_name, selected_text)
            return JsonResponse({"status": True, "data": insert_reply(reply_content)})
    # 处理m2m字段
    if name in ['attention']:
        # {"name":"attention","value":[1,2,3]}  数据格式，先判断数据格式是否正确
        if not isinstance(value, list):
            return JsonResponse({"status": False, "error": "数据格式错误"})
        # 传递过来的值为空
        if not value:
            # 判断数据库是否允许为空
            if not fields_object.null:
                # 当数据库不允许为空的时候
                return JsonResponse({"status": False, "errors": "该项不允许为空"})
            else:
                # 当数据库允许为空的时候，设置None 并 save
                try:
                    # setattr(issues_object, name, None)  #m2m 设置为空的时候不能用None
                    # setattr(issues_object, name, [])  #m2m 为空 可以 用 空列表
                    issues_object.attention.set(value)  # m2m 或者这样
                    issues_object.save()
                except TypeError:
                    print("报错--=-=-=-=-=-=-=-=")
                reply_content = "{}更新为空".format(fields_object.verbose_name)
                return JsonResponse({"status": True, "data": insert_reply(reply_content)})
        else:
            # 传递过来的值不为空
            # values=["1","2,3,4]  ->   id是否是项目成员（参与者、创建者）
            # 先获取项目的所有成员，包括项目的创建者
            user_dict = {str(request.tracer.project.create_user_id): request.tracer.project.create_user.user_name}
            user_object_list = models.ParticipatorInfo.objects.filter(project_id=project_id)
            for item in user_object_list:
                user_dict[str(item.participator_id)] = item.participator.user_name
                # print(str(item.participator_id), item.participator.user_name)
            # 判断传递过来的值是否在 所有成员里面
            user_name_list = []  # 用于存放返回前端的用户名
            for user_id in value:
                user_name = user_dict.get(str(user_id))
                if not user_name:
                    return JsonResponse({"status": False, "errors": "该用户不存在"})
                user_name_list.append(user_name)
            # setattr(issues_object, name, value)
            issues_object.attention.set(value)
            issues_object.save()
            reply_content = "{}更新为{}".format(fields_object.verbose_name, ','.join(user_name_list))
        return JsonResponse({"status": True, "data": insert_reply(reply_content)})
    # 如果 传递了其他字段则
    return JsonResponse({"status": False, "errors": "你想干嘛？？？"})


# ''' 项目成员邀请-生成邀请码 '''
def invite_url(request, project_id):
    if request.method == "POST":
        """
        1.限制：只有项目创建者才能生成邀请码
        2.生成随机邀请码
        3.保存到数据库，并生成url链接返回给前端
        """
        form = InviteModelForm(data=request.POST)
        if form.is_valid():
            # 限制：只有项目创建者才能生成邀请码
            if request.tracer.user != request.tracer.project.create_user:
                form.add_error('validity_period', "无权创建邀请码")
                return JsonResponse({"status": False, "errors": form.errors})
            form.instance.creator = request.tracer.user
            form.instance.project = request.tracer.project
            form.instance.code = uid(request.tracer.user.mobile_phone)
            form.save()
            url = "{scheme}://{host}{path}".format(
                scheme=request.scheme,  # 获取http https
                host=request.get_host(),
                path=reverse("invite_join", kwargs={"code": form.instance.code})
            )

            return JsonResponse({"status": True, "data": url})

    # 如果是get请求这个接口，则

    return redirect(reverse("error_url"))


def invite_join(request, code):
    if request.method == "GET":
        current_datetime = datetime.datetime.now()
        """
        1.判断邀请码是否存在
        2.判断邀请码有效期
        3.判断邀请码可用次数
        4.判断当前用户是否已经加入了该项目
        5.判断当前用户是否项目创建者，如果是则提示“创建者无需加入项目”
        6.判断项目成员是否超限定的数量，在这之前先得判断购买的套餐是否到期
        7.判断邀请码是否有使用数量限制，如有则判断已使用的数量是否达到限定的数量
        """
        # 1.判断邀请码是否存在
        invite_object = models.ProjectInvite.objects.filter(code=code).first()
        if not invite_object:
            return render(request, "invite_join.html", {'errors': "邀请码不存在"})
        # 5.判断当前用户是否项目创建者，如果是则提示“创建者无需加入项目”
        if invite_object.project.create_user == request.tracer.user:
            return render(request, 'invite_join.html', {'errors': '创建者无需再加入项目'})
        # 4.判断当前用户是否已经加入了该项目
        exists = models.ParticipatorInfo.objects.filter(project=invite_object.project,
                                                        participator=request.tracer.user).exists()
        if exists:
            return render(request, 'invite_join.html', {'errors': '已加入项目无需再加入'})
        # 2.判断有效期
        validity_period = invite_object.validity_period  # 5 30 60 1440 分钟
        create_datetime = invite_object.create_datetime  # 创建时间
        limit_datetime = create_datetime + datetime.timedelta(minutes=validity_period)
        # 当前时间 2023-03-15 11:50:30.754226 创建时间 2023-03-15 09:57:42.663252 过期时间 2023-03-15 10:57:42.663252
        # print("当前时间", current_datetime, "创建时间", create_datetime, "过期时间", limit_datetime)
        if current_datetime > limit_datetime:
            return render(request, "invite_join.html", {'errors': "邀请码已过期"})
        # 6.判断项目成员是否超限定的数量，在这之前先得判断购买的套餐是否到期
        max_join_user_num = 0
        # 先获取项目已经有多少人参与了
        has_join_user_count = models.ParticipatorInfo.objects.filter(project=invite_object.project).count()
        has_join_user_count += 1  # 当然包含项目创建者占用的数量1
        # 根据项目的创建者获取该创建者的订单情况
        orderinfo = models.OrderInfo.objects.filter(create_user=invite_object.project.create_user).order_by(
            "-id").first()
        if orderinfo.price.category == 1:
            # 使用的是免费版，则获取免费版的每项目允许参与的人员个数，免费版目前定义的是5个
            print("项目邀请者使用的是免费版，每项目允许：", orderinfo.price.project_members, "当前项目已经有：", has_join_user_count, "个人参与")
            max_join_user_num = orderinfo.price.project_members
        else:
            if orderinfo.end_time < current_datetime:
                # 表示收费版已经过期
                free_object = models.Price.objects.filter(category=1).first()
                max_join_user_num = free_object.project_members
            else:
                max_join_user_num = orderinfo.price.project_members
        if has_join_user_count >= max_join_user_num:
            return render(request, "invite_join.html", {"errors": "项目成员超限，请升级套餐"})
        # 7.判断邀请码是否有使用数量限制，如有则判断已使用的数量是否达到限定的数量
        if invite_object.count:
            # 表示邀请码有数量限制
            if invite_object.use_count >= invite_object.count:
                return render(request, "invite_join.html", {"errors": "邀请码使用次数已达到上限"})
            else:
                invite_object.use_count += 1    # 邀请码使用次数+1
                invite_object.save()
        # 向项目参与者表插入一条记录
        models.ParticipatorInfo.objects.create(
            project=invite_object.project,
            participator=request.tracer.user,
            inviter=invite_object.project.create_user
        )
        # 项目信息表参与者数量+1
        invite_object.project.participators +=1
        invite_object.project.save()
        return render(request, "invite_join.html", {'project': invite_object.project})
    return redirect(reverse("error_url"))
